#include "Preprocessor.h"
#include <iostream>
#include <math.h>

#include "cocoslib.h"
#include "Config.h"

int GetXOffsetFromShear(double degrees, int yOffset){  
  #ifdef DEBUG
  cout << "Entering method GetXOffsetFromShear" << endl;
  #endif
  double factor = tan(degrees/180*M_PI);
  #ifdef DEBUG
  cout << "Entering method GetXOffsetFromShear" << endl;
  #endif
  return (int)floor(yOffset * factor);
}

PamImage Shear(PamImage& inImage, double degrees){
  #ifdef DEBUG
  cout << "Entering method Shear" << endl;
  #endif
  double factor = tan(degrees/180*M_PI);
  long outHeight = inImage.getHeight();
  int initShift = (int)floor(outHeight * factor);
  long inWidth = inImage.getWidth();
  long outWidth = inWidth + initShift;
  
  PamImage outImage(inImage.getImageType(), outWidth, outHeight);
  for(int yIndex = 0; yIndex < outHeight; yIndex++){
    int shift = (int)floor((outHeight - yIndex) * factor);
    for(int xIndex = 0; xIndex < outWidth; xIndex++){
      int inX = xIndex+shift-initShift;
      if(0 <= inX && inX < inWidth){
        outImage.putPixel(xIndex, yIndex, inImage.getPixelGray(inX, yIndex));
      }else{
        outImage.putPixel(xIndex, yIndex, 255);
      }
    }
  }
  #ifdef DEBUG
  cout << "Entering method Shear" << endl;
  #endif
  return outImage;
}

PamImage RemoveSmallConnectedComponents(PamImage& image)
{
  #ifdef DEBUG
  cout << "Entering method RemoveSmallConnectedComponents" << endl;
  #endif
  Cocos cocos(&image,8,0);  
  int cocosNum = cocos.getNum();  
  bool componentRemoved = true;
  while(componentRemoved){
    componentRemoved = false;
    for(int i = 0; i < cocosNum; i++){
      if(cocos.getSurface(i) < Config::getInstance()->minimumConnectedComponentSize)
      {
	      cocos.remove(i);
	      componentRemoved = true;
	      break;
      }
    }
    cocosNum = cocos.getNum(); 
  }
  PamImage outputImage = *cocos.getImage();
  #ifdef DEBUG
  cout << "Entering method RemoveSmallConnectedComponents" << endl;
  #endif
  return outputImage;
}

PamImage* Dilate(PamImage* image, int size){
  #ifdef DEBUG
  cout << "Entering method Dilate" << endl;
  #endif
  int width = image->getWidth();
  int height = image->getHeight();
  GrayPixel** pixels = image->getGrayPixels();
  PamImage* outputImage = new PamImage(GRAY_IMAGE, width, height);
  for(long xIndex = 0; xIndex < width; xIndex++){
    for(long yIndex = 0; yIndex < height; yIndex++){
      int localMinimum = 255;
      for(int i = -size; i <= size; i++){
	long localX = xIndex + i;
	if(localX < 0) localX = 0;
	if(width <= localX)localX = width - 1;
	for(int j = -size; j <= size; j++){
	  long localY = yIndex + j;
	  if(localY < 0) localY = 0;
	  if(height <= localY)localY = height - 1;
	  GrayPixel pixel = pixels[localY][localX];
	  if(pixel < localMinimum)localMinimum = int(pixel);
	}
      }
      outputImage->putPixel(xIndex, yIndex, localMinimum);
    }
  }
  #ifdef DEBUG
  cout << "Entering method Dilate" << endl;
  #endif
  return outputImage;
}

PamImage* GetRedChanel(PamImage* inImage){
  #ifdef DEBUG
  cout << "Entering method GetRedChanel" << endl;
  #endif
  long width = inImage->getWidth();
  long height = inImage->getHeight();
  RGBPixel** pixels = inImage->getRGBPixels();
  
  PamImage* redChanelImage = new PamImage(GRAY_IMAGE, width, height);
  for(long xIndex = 0; xIndex < width; xIndex++){
    for(long yIndex = 0; yIndex < height; yIndex++){
      RGBPixel pixel = pixels[yIndex][xIndex];
      redChanelImage->putPixel(xIndex, yIndex,pixel.r);      
    }
  }
  #ifdef DEBUG
  cout << "Entering method GetRedChanel" << endl;
  #endif
  return redChanelImage;
}

PamImage* ThresholdGrayImage(PamImage* inImage, int threshHoldValue){
  #ifdef DEBUG
  cout << "Entering method ThresholdGrayImage" << endl;
  #endif
  //inImage = inImage->convert(2);
  long width = inImage->getWidth();
  long height = inImage->getHeight();
  GrayPixel** pixels = inImage->getGrayPixels();
  
  PamImage* threshHoldImage = new PamImage(1, width, height);
  for(long xIndex = 0; xIndex < width; xIndex++){
    for(long yIndex = 0; yIndex < height; yIndex++){
      GrayPixel pixel = pixels[yIndex][xIndex];
      if(threshHoldValue < pixel){
	threshHoldImage->putPixel(xIndex, yIndex,255);
      }
    }
  }
  #ifdef DEBUG
  cout << "Entering method ThresholdGrayImage" << endl;
  #endif
  return threshHoldImage;
}
